//
//  YXPlayerDownloadManger.swift
//  swift_wobo
//
//  Created by yuxin on 2018/12/2.
//  Copyright © 2018 wuxiantianli. All rights reserved.
//

import UIKit

protocol YXPlayerDownloadMangerDelegate: class {
    func download(downloadManger: YXPlayerDownloadManger, didReceiveResponse response: URLResponse)
    func download(downloadManger: YXPlayerDownloadManger, didReceiveData data: Data)
    func download(downloadManger: YXPlayerDownloadManger, didFinishedWithError error: Error?)
}
class YXPlayerDownloadManger: NSObject {
    private var cacheWorker: YXPlayerCacheWorker
    
    private var sessionManager: YXPlayerDownloadSessionManger?
    private var session: URLSession?
    private var task: URLSessionDataTask?
    
    private var actionList = [YXPlayerAction]()
    private var videoUrl: URL
    
    var isCancelled: Bool = false
    var startOffset: Int = 0
    weak var delegate: YXPlayerDownloadMangerDelegate?
    
    init(url: URL) {
        
        videoUrl = url
        cacheWorker = YXPlayerCacheWorker(url: url)
        
        super.init()
        
        sessionManager = YXPlayerDownloadSessionManger(delegate: self)
        let sessionConfiguration = URLSessionConfiguration.default
        let s = URLSession(configuration: sessionConfiguration, delegate: sessionManager, delegateQueue: YXPlayerCacheManger.shared.downloadQueue)
        session = s
    }
    
    func start(forRange range:NSRange){
        let actions = cacheWorker.cachedDataActions(forRange: range)
        actionList = actions
        processActions()
    }
    
    func cancel() {
        session?.invalidateAndCancel()
        isCancelled = true
    }
    
}

extension YXPlayerDownloadManger {
    
    private func processActions() {
        if isCancelled {
            return
        }
        
        if let action = actionList.first {
            actionList.removeFirst()
            if action.type == YXPlayerActionType.local {
                if let data = cacheWorker.getCacheData(forRange: action.range) {
                    delegate?.download(downloadManger: self, didReceiveData: data)
                    processActions()
                }else {
                    let error = NSError(domain: "com.vgplayer.downloadActionWorker", code: -1, userInfo: [NSLocalizedDescriptionKey: "Read cache data failed."]) as Error
                    delegate?.download(downloadManger: self, didFinishedWithError: error)
                }
            }else {
               loadRemoteData(action: action)
            }
            
        }else {
            delegate?.download(downloadManger: self, didFinishedWithError: nil)
        }
    }
    
    // 下载远程数据片段action
    private func loadRemoteData(action: YXPlayerAction) {
        let fromOffset = action.range.location
        let endOffset = action.range.location + action.range.length - 1
        var request = URLRequest(url: videoUrl)
        request.cachePolicy = .reloadIgnoringLocalAndRemoteCacheData //   local and remote cache policy 缓存策略
        let range = String(format: "bytes=%lld-%lld", fromOffset, endOffset)
        request.setValue(range, forHTTPHeaderField: "Range")        // set HTTP Header
        
        startOffset = action.range.location
        task = self.session?.dataTask(with: request)
        task?.resume()
    }
    
    
    
}

extension YXPlayerDownloadManger: YXPlayerDownloadSessionMangerDelegate {
    func yx_urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        
        let card = URLCredential(trust: challenge.protectionSpace.serverTrust!)
        completionHandler(URLSession.AuthChallengeDisposition.useCredential, card)
    }
    
    func yx_urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
        
        if let mimeType = response.mimeType {
            if  (mimeType.range(of: "video/") == nil),
                (mimeType.range(of: "audio/") == nil),
                (mimeType.range(of: "application/") == nil) {
                completionHandler(.cancel)
            }else {
                delegate?.download(downloadManger: self, didReceiveResponse: response)
                cacheWorker.startWritting()
                completionHandler(.allow)
            }
        }else {
            completionHandler(.cancel)
        }
        
    }
    
    func yx_urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
        if isCancelled {
            return
        }
        
        let range = NSRange(location: startOffset, length: data.count)
        if let error = cacheWorker.setCacheData(forRange: range, data: data) {
            delegate?.download(downloadManger: self, didFinishedWithError: error)
        } else {
            cacheWorker.save()
        }
       
        startOffset += data.count
        delegate?.download(downloadManger: self, didReceiveData: data)
        
        //todo:外部更新进度
    }
    
    func yx_urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        cacheWorker.finishWritting()
        cacheWorker.save()
        
        if error != nil {
            delegate?.download(downloadManger: self, didFinishedWithError: error)
            //todo:外部出错
        }else{
            processActions()
            //todo:外部更新进度
        }
    }
    
    
}
